#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <GL/glut.h>

#include "readoff.h"
#include "readppm.h"
#include "ChessPiece.h"

ChessPiece::ChessPiece(char* offFileLocation) {
	offFile = offFileLocation;

	// load the off file
	loadOffFile(offFile);

	fprintf(stderr, "Received the argument %s\n", offFileLocation);
	
	rotationAmount.x = rotationAmount.y = rotationAmount.z = 0.0;
	rotationAngle = 0.0;
}

void ChessPiece::draw() {

	glTranslated(centerLocation.x, centerLocation.y, centerLocation.z);
	glRotated(rotationAngle, rotationAmount.x, rotationAmount.y, rotationAmount.z);

	int faceIndex;
	for (faceIndex = 0; faceIndex < my3dObject.Nfaces; faceIndex++) {

		// draw the face now
		glNormal3f(faceNormals[faceIndex].x, faceNormals[faceIndex].y,
				faceNormals[faceIndex].z);

		int index;

		int numberOfVertices = my3dObject.nv_face[faceIndex];
		glBegin(GL_POLYGON);

		for (index = 0; index < numberOfVertices; index++) {
			// map the texture to our cordinates. 
			if (index == 0)
				glTexCoord2d(0, 0);
			else if (index == 1)
				glTexCoord2d(1, 0);
			else if (index == 2)
				glTexCoord2d(1, 1);
			else
				glTexCoord2d(0, 1);

			// draw the vertex
			glVertex3d(
					my3dObject.vertices[my3dObject.faces[faceIndex][index]].x,
					my3dObject.vertices[my3dObject.faces[faceIndex][index]].y,
					my3dObject.vertices[my3dObject.faces[faceIndex][index]].z);

		}
		glEnd();
	}
}

void ChessPiece::setCenterLocations(GLdouble x, GLdouble y, GLdouble z) {
	centerLocation.x = x;
	centerLocation.y = y;
	centerLocation.z = z;
}

void ChessPiece::rotate(GLdouble angle, GLdouble x, GLdouble y, GLdouble z){
	rotationAngle = angle;
	rotationAmount.x = x;
	rotationAmount.y = y;
	rotationAmount.z = z;
}

/////////////////////////////////////////////////////
//     U T I L  M E T H O D S
////////////////////////////////////////////////////
Vector3 ChessPiece::constructVector(HPoint3 start, HPoint3 end) {
	Vector3 newVector;
	newVector.x = end.x - start.x;
	newVector.y = end.y - start.y;
	newVector.z = end.z - start.z;
	return newVector;
}

Vector3 ChessPiece::performCrossProduct(Vector3 v1, Vector3 v2) {
	Vector3 v;
	v.x = v1.y * v2.z - v1.z * v2.y;
	v.y = v1.z * v2.x - v1.x * v2.z;
	v.z = v1.x * v2.y - v1.y * v2.x;
	return v;
}

Vector3 ChessPiece::normalizeVector(Vector3 inVec) {
	Vector3 outVec;

	double reciprocal = sqrt(pow(inVec.x, 2) + pow(inVec.y, 2)
			+ pow(inVec.z, 2));
	outVec.x = inVec.x / reciprocal;
	outVec.y = inVec.y / reciprocal;
	outVec.z = inVec.z / reciprocal;
	return outVec;

}

Vector3 ChessPiece::createFaceNormal(int faceIndex) {
	HPoint3 point_1 = my3dObject.vertices[my3dObject.faces[faceIndex][0]];
	HPoint3 point_2 = my3dObject.vertices[my3dObject.faces[faceIndex][1]];
	HPoint3 point_3 = my3dObject.vertices[my3dObject.faces[faceIndex][2]];

	Vector3 vec1, vec2, returnVec;

	// get two vectors
	vec1 = constructVector(point_1, point_2);
	vec2 = constructVector(point_1, point_3);

	// perform the cross product to get the normal vector
	returnVec = performCrossProduct(vec1, vec2);

	// normalize the normal vector
	return normalizeVector(returnVec);

}

void ChessPiece::loadOffFile(char *offFile) {

	if (strcmp(offFile, "")) {
		printf("Processing the OFF file %s.\n", offFile);
		ReadOFF(offFile, &my3dObject);
	} else {
		printf("No OFF file given. Using the default cube OFF file.\n");
		ReadOFF("cube.off", &my3dObject);
	}

	// initialize face normal array to contain required number of normals.
	int numberOfFaces = my3dObject.Nfaces;
	faceNormals = (Point3 *) malloc(my3dObject.Nfaces*sizeof(Point3));;

	// now for each face calculate the normals
	int index = 0;
	for (index = 0; index < numberOfFaces; index++) {
		faceNormals[index] = createFaceNormal(index);
	}

	//calculate the center of mass, so that we can do all the rotations around this.
	for (index = 0; index < my3dObject.Nvertices; index++) {
		HPoint3 vertex = my3dObject.vertices[index];
		centerOfMass.x += vertex.x;
		centerOfMass.y += vertex.y;
		centerOfMass.z += vertex.z;
	}
	centerOfMass.x = (double) centerOfMass.x / my3dObject.Nvertices;
	centerOfMass.y = (double) centerOfMass.y / my3dObject.Nvertices;
	centerOfMass.z = (double) centerOfMass.z / my3dObject.Nvertices;

	fprintf(stderr, "Center of mass is at [%d, %d, %d]\n", centerOfMass.x, centerOfMass.y, centerOfMass.z);

}
